
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                               proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                                    Forrest Yu, 2005
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include "type.h"
#include "const.h"
#include "protect.h"
#include "tty.h"
#include "console.h"
#include "string.h"
#include "proc.h"
#include "global.h"
#include "proto.h"

/*======================================================================*
                              schedule
 *======================================================================*/
SEMAPHORE read;
SEMAPHORE rdmutex;
SEMAPHORE read_wait;
SEMAPHORE write;
SEMAPHORE wdmutex;
SEMAPHORE readnummutex;
SEMAPHORE * sp_readnummutex;
SEMAPHORE * sp_read;
SEMAPHORE * sp_rdmutex;
SEMAPHORE * sp_read_wait;
SEMAPHORE * sp_write;
SEMAPHORE * sp_wdmutex;
SEMAPHORE read_first;
SEMAPHORE * sp_read_first;
int rcount = 0;
int wcount = 0;
int readnum=0;
int writenum=0;

PUBLIC void schedule()
{
	PROCESS* p;
	int	 greatest_ticks = 0;

	for (p = proc_table; p < proc_table+NR_TASKS; p++) {
		if(p -> sleep > 0){
			p -> sleep--;//减掉睡眠的时间
		}
	}
	while (!greatest_ticks) {
		for (p = proc_table; p < proc_table+NR_TASKS; p++) {
			if (p -> wait>0 || p -> sleep>0){
				continue;//若在等待状态或有睡眠时间，就不分配时间片
			}
			if (p->ticks > greatest_ticks) {
				greatest_ticks = p->ticks;
				p_proc_ready = p;
			}
		}

		if (!greatest_ticks) {

			for (p = proc_table; p < proc_table+NR_TASKS; p++) {
				if (p -> wait>0 || p -> sleep>0){
					continue;//若在等待状态或有睡眠时间，就不分配时间片
				}
				p->ticks = p->priority;
			}
		}
	}
}

/*======================================================================*
                           sys_get_ticks
 *======================================================================*/
PUBLIC int sys_get_ticks()
{

	return ticks;
}

PUBLIC int  sys_disp_str(char * str){
	TTY*	p_tty=tty_table;
	int i=0;
    int z=p_proc_ready - proc_table - 3;
	while(str[i]!='\0'){
	    out_char_color(p_tty->p_console,str[i],z);
	    i++;
	}

}

PUBLIC int sys_process_sleep(int k){
	p_proc_ready -> sleep=k;
    schedule();
	return 0;
}

PUBLIC int sys_P(SEMAPHORE* t){

   t->s--;
   if(t->s<0){
	   p_proc_ready ->wait=1;
	   t->x[t->ptr]=p_proc_ready;
	   t->ptr++;//进入等待进程队列

	   schedule();
   }
}

PUBLIC int sys_V(SEMAPHORE* t){
   t->s++;
   if(t->s<=0){
   	t->x[0]->wait=0;
   	for(int i=0;i<t->ptr;i++){
   	    t->x[i]=t->x[i+1];
   	}
   	t->ptr--;
   }
}

PUBLIC void readSemaphore() {
	read.s =read_wait.s=2;
	rdmutex.s = 1;
	readnummutex.s=1;
	sp_readnummutex=&readnummutex;
    sp_rdmutex = &rdmutex;
    sp_read = &read;
	sp_read_wait = &read_wait;
	read_first.s = 1;
	rcount=0;
	readnum=0;
	sp_read_first = &read_first;
}

PUBLIC void writeSemaphore() {
	wcount=0;
	write.s = 1;
	writenum=0;
	wdmutex.s = 1;
	sp_wdmutex = &wdmutex;
	sp_write = &write;

}

PUBLIC void write_reader(char * name,int time){
  
		
		system_P(sp_write);
		writenum++;
		//开始写
		system_disp_str(name, 1);
	    system_disp_str(" begans to write\n",1);
       
		//写操作
		system_disp_str(name, 1);
		system_disp_str(" is writing\n", 1);
	    system_process_sleep(1000*time);
		

		//写结束
		system_disp_str(name, 1);
		system_disp_str(" finishs writing\n", 1);
		writenum--;
	    system_V(sp_write);
	   
		

   
}


PUBLIC void read_reader(char * name, int time) {
	
		system_P(sp_rdmutex);
		rcount++;
		if (rcount == 1) {
			
			system_P(sp_write);
			system_V(sp_rdmutex);
		}
		else {
			system_V(sp_rdmutex);
		}

		system_P(sp_read);
		//开始读
		system_P(sp_readnummutex);
		readnum++;
		system_V(sp_readnummutex);
		
		system_disp_str(name, 1);
		system_disp_str(" begans to read\n", 1);

		//读操作
		system_disp_str(name, 1);
		system_disp_str(" is reading\n", 1);
		system_process_sleep(1000 * time);
		system_P(sp_readnummutex);
		readnum--;
		system_V(sp_readnummutex);
		system_V(sp_read);

		//读结束
		system_disp_str(name, 1);
		system_disp_str(" finishs reading\n", 1);

		system_P(sp_rdmutex);
		rcount--;
		if (rcount == 0) {
			system_V(sp_write);
			system_V(sp_rdmutex);
			
		}
		else {
			system_V(sp_rdmutex);
		}
	
}

PUBLIC void write_writer(char * name, int time) {
	
		system_P(sp_wdmutex);
		wcount++;
		if (wcount == 1) {
			system_V(sp_wdmutex);
			system_P(sp_read_first);
		}
		else {
			system_V(sp_wdmutex);
		}


		system_P(sp_write);
		writenum++;
		//开始写
		system_disp_str(name, 1);
		system_disp_str(" begins to write\n", 1);

		//写操作
		system_disp_str(name, 1);
		system_disp_str(" is writing\n", 1);
		system_process_sleep(1000 * time);
		writenum--;
		system_V(sp_write);

		//写结束
		system_disp_str(name, 1);
		system_disp_str(" finishes writing\n", 1);

		system_P(sp_wdmutex);
		wcount--;
		if (wcount == 0) {
			system_V(sp_wdmutex);
			system_V(sp_read_first);
		}
		else {
			system_V(sp_wdmutex);
		}
	
}

PUBLIC void read_writer(char * name, int time) {
	
		system_P(sp_read_wait);
		system_P(sp_read_first);
		system_P(sp_rdmutex);
		rcount++;
		if (rcount == 1) {
			system_V(sp_rdmutex);
			system_V(sp_read_first);
			system_P(sp_write);
		}
		else {
			system_V(sp_rdmutex);
			system_V(sp_read_first);
		}
		

		system_P(sp_read);
		system_P(sp_readnummutex);
		readnum++;
		system_V(sp_readnummutex);
		//开始读
		system_disp_str(name, 1);
		system_disp_str(" begins to read\n", 1);

		//读操作
		
		system_disp_str(name, 1);
		system_disp_str(" is reading\n", 1);
		system_process_sleep(1000 * time);
		system_P(sp_readnummutex);
		readnum--;
		system_V(sp_readnummutex);
		system_V(sp_read);
		system_V(sp_read_wait);
		//读结束
		system_disp_str(name, 1);
		system_disp_str(" finishs reading\n", 1);

		system_P(sp_rdmutex);
		rcount--;
		if (rcount == 0) {
			system_V(sp_rdmutex);
			system_V(sp_write);
		}
		else {
			system_V(sp_rdmutex);
		}
	
}
PUBLIC void get_mutex() {
	
	if (writenum != 0) {
		system_disp_str("This book is written\n", 1);
	}
	if (readnum != 0) {
		system_disp_str("This book is read by ", 1);
		if(readnum==3){
			system_disp_str("3",1);
		}
		if(readnum==2){
			system_disp_str("2",1);
		}
		if(readnum==1){
			system_disp_str("1",1);
		}
		system_disp_str(" people\n",1);
	}

}